﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NewsMine.Utilities;
using System.IO;

namespace NewsMine.Storage.SQLite
{
    public class SQLiteKeyValueStore : IKeyValueStore
    {
        string storeDirectory;
        SQLiteKeyValueHelper sqliteKeyValueHelper;

        [Obsolete("This is exposed only for maintanance task.")]
        public SQLiteKeyValueHelper GetSqliteHelperClass()
        {
            return sqliteKeyValueHelper;
        }

        [Obsolete("This is exposed only for maintanance task.")]
        public string GetStoreDirectory()
        {
            return storeDirectory;
        }

        object syncLock = new object();

        #region Constructor

        public SQLiteKeyValueStore(string _storeDirectory)
        {
            if (string.IsNullOrEmpty(_storeDirectory))
                throw new ApplicationException("Invalid directory to create SQLiteKeyValueStore.");

            if (!Directory.Exists(_storeDirectory))
            {
                Directory.CreateDirectory(_storeDirectory);
            }

            storeDirectory = _storeDirectory;

            sqliteKeyValueHelper = new SQLiteKeyValueHelper(Path.Combine(storeDirectory, "sqliteKVItems.db"));
        }


        #endregion

        #region IKeyValueStore API implementation

        public void Open()
        {
            //todo: this method may not required for the sqlite, this can be removed later.
        }

        public void Close()
        {
            //todo: this method may not required for the sqlite, this can be removed later.
        }

        public void Set(string key, object obj)
        {
            lock (syncLock)
            {
                AddItemToSQLiteKeyValueDB(new KeyValueItem { Key = key, Value = new ValueItem { Value = obj } });
            }
        }

        public void SetMultiple(Dictionary<string, object> keyValueDictionary)
        {
            lock (syncLock)
            {
                var result = new List<KeyValueItem>();

                foreach (var k in keyValueDictionary.Keys)
                {
                    result.Add(new KeyValueItem { Key = k, Value = new ValueItem { Value = keyValueDictionary[k] } });
                }

                AddItemsToSQLiteKeyValueDB(result);
            }
        }

        public object Get(string key)
        {
            lock (syncLock)
            {
                var value = GetKeyValueItemFromSqliteByKey(key);

                return value;
            }
        }

        public List<object> GetAll()
        {
            lock (syncLock)
            {
                return GetAllItemsFromSQLiteDB();
            }
        }

        public List<object> Get(int startIndex, int length)
        {
            lock (syncLock)
            {
                var allItemsInStore = GetAll();

                if (allItemsInStore == null || allItemsInStore.Count == 0)
                    return new List<object>();

                var result = (from item in allItemsInStore
                              select item).Skip(startIndex).Take(length).ToList();

                return result;
            }
        }

        public int GetCount()
        {
            lock (syncLock)
            {
                return sqliteKeyValueHelper.GetCount();
            }
        }

        public void Replace(string key, object obj)
        {
            Set(key, obj);
        }

        public void ReplaceMultiple(Dictionary<string, object> keyValueDictionary)
        {
            SetMultiple(keyValueDictionary);
        }

        public void Delete(string key)
        {
            DeleteItemFromSQLiteDB(key);
        }

        public bool IsKeyExists(string key)
        {
            lock (syncLock)
            {
                return sqliteKeyValueHelper.IsExists(key);
            }
        }

        #endregion

        #region SQLite mechanism


        //todo: now
        private void AddItemToSQLiteKeyValueDB(KeyValueItem keyValueItem)
        {
            sqliteKeyValueHelper.Set(keyValueItem.Key, ObjectByteArrayConverter.ObjectToByteArray(keyValueItem));
        }


        //todo: now
        private void AddItemsToSQLiteKeyValueDB(List<KeyValueItem> keyValueItems)
        {
            foreach (var item in keyValueItems)
            {
                AddItemToSQLiteKeyValueDB(item);
            }
        }

        private object GetKeyValueItemFromSqliteByKey(string key)
        {
            lock (syncLock)
            {
                var data = sqliteKeyValueHelper.Get(key);

                if (data == null)
                    return null;

                KeyValueItem kvItem = (KeyValueItem)ObjectByteArrayConverter.ByteArrayToObject(data);

                if (kvItem == null)
                    return null;

                return kvItem.Value.Value;
            }
        }

        private List<object> GetAllItemsFromSQLiteDB()
        {
            lock (syncLock)
            {
                var allItems = sqliteKeyValueHelper.GetAll();

                List<KeyValueItem> resultKeyValueItems = new List<KeyValueItem>();

                foreach (var item in allItems)
                {
                    resultKeyValueItems.Add((KeyValueItem)NewsMine.Utilities.ObjectByteArrayConverter.ByteArrayToObject(item));
                }

                List<object> result = new List<object>();

                foreach (var item in resultKeyValueItems)
                {
                    result.Add(item.Value.Value);
                }

                return result;
            }
        }

        private void DeleteItemFromSQLiteDB(string key)
        {
            lock (syncLock)
            {
                sqliteKeyValueHelper.DeleteByKey(key);
            }
        }

        #endregion








        public object Get(string key, bool forceLatest)
        {
            var value = GetKeyValueItemFromSqliteByKey(key);

            lock (syncLock)
            {

                if (value == null)
                {
                    //try to get from it from the un stored serialization collection.

                    var data = sqliteKeyValueHelper.GetEvenItIsInUnsavedItemFromSerializedFile(key);

                    if (data == null)
                        return null;

                    KeyValueItem kvItem = (KeyValueItem)ObjectByteArrayConverter.ByteArrayToObject(data);

                    return kvItem.Value.Value;
                }
            }

            return value;
        }
    }
}
